package cn.wolfcode.shop.web.controller;


import cn.wolfcode.shop.domain.OrderInfo;
import cn.wolfcode.shop.domain.SeckillOrder;
import cn.wolfcode.shop.domain.User;
import cn.wolfcode.shop.mq.OrderMessage;
import cn.wolfcode.shop.redis.RedisServer;
import cn.wolfcode.shop.redis.SeckillGoodKeyPrefix;
import cn.wolfcode.shop.redis.SeckillOrderKeyPrefix;
import cn.wolfcode.shop.result.CodeMsg;
import cn.wolfcode.shop.service.IOrderInfoService;
import cn.wolfcode.shop.service.ISeckillGoodService;
import cn.wolfcode.shop.service.ISeckillOrderService;
import cn.wolfcode.shop.service.ISeckillService;
import cn.wolfcode.shop.vo.GoodVo;
import cn.wolfcode.shop.web.mq.MQSender;
import cn.wolfcode.shop.web.result.Result;
import cn.wolfcode.shop.web.util.AccessLimit;
import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@Controller
@RequestMapping("seckill")
public class SeckillController {
    @Reference
    private ISeckillGoodService seckillGoodService;
    @Reference
    private ISeckillOrderService seckillOrderService;
    @Reference
    private ISeckillService seckillService;
    @Reference
    private IOrderInfoService orderInfoService;
    @Autowired
    private RedisServer redisServer;
    @Autowired
    private MQSender mqSender;
    //本地标记,当秒杀结束进行标记,不再去远程redis查询数据
    public static ConcurrentHashMap<String,Boolean> localSign = new ConcurrentHashMap<>();
    @AccessLimit(seconds = 5,maxCount = 5,needLogin = true)
    @RequestMapping("/getPath")
    public Result<String> getPath(User user,Long goodId,String verifyCode){
        if(user==null){
            return Result.error(CodeMsg.TOKEN_INVALID);
        }
        Integer result = null;
        try {
            result = Integer.parseInt(verifyCode);
        }catch (Exception e){
            return Result.error(CodeMsg.VERIFYCODE_ERROR);
        }
        Integer oldResult = redisServer.get(SeckillGoodKeyPrefix.SECKILL_VERIFYCODE_RESULT, user.getId() + ":" + goodId, int.class);
        if(oldResult==null || result - oldResult !=0 ){
            return Result.error(CodeMsg.VERIFYCODE_ERROR);
        }
        //生成随机字符串
        String uuid = UUID.randomUUID().toString().replace("-","");
        //将随机随机字符串 保存redis 中 key为用户的id,和被秒杀商品的id组合成
        //当用户登录秒杀的时候,判断redis中的此用户商品 的 uuid,是否和当前用户请求地址上的uuid一致
        redisServer.set(SeckillGoodKeyPrefix.SECKILL_GET_PATH,user.getId()+":"+goodId,uuid);
        return Result.success(uuid);
    }
    /**
     * 做秒杀时的操作
     * @param user
     * @param goodId
     * @return
     */
    @RequestMapping("/{realPath}/do_seckill")
    @ResponseBody
    public Result<String> do_seckill(User user,String uuid, Long goodId,@PathVariable("realPath") String realPath){
        //用户如果没有登录,则返回登录界面
        if(user==null){
            return Result.error(CodeMsg.TOKEN_INVALID);
        }
        //查询本地是否已被标记秒杀活动结束
        Boolean isOver = localSign.get(SeckillGoodKeyPrefix.GOOD_STOCK + goodId);
        if(isOver !=null && isOver){
            return Result.error(CodeMsg.SECKILL_OVER);
        }
        //先判断是否是否登录,和秒杀活动是否标记已经结束,不然不要白白去远程redis
        String oldPath = redisServer.get(SeckillGoodKeyPrefix.SECKILL_GET_PATH,user.getId()+":"+goodId,String.class);
        if(oldPath == null ||!oldPath.equals(realPath)){
            return Result.error(CodeMsg.SECKILL_ERROR);
        }
        GoodVo goodVo = seckillGoodService.getCacheByGoodId(goodId);
        if(goodVo == null){
            return Result.error(CodeMsg.ILLEAGE_OP);
        }
        //如果秒杀未开始,则表示当前操作非法
        if(goodVo.getStartDate().getTime() - new Date().getTime() > 0){
            return Result.error(CodeMsg.ILLEAGE_OP);
        }
        //同一用户不可重复秒杀判断 查询当前用户是否已经秒杀过此商品
        SeckillOrder seckillOrder = redisServer.get(SeckillOrderKeyPrefix.SECKILL_ORDER,user.getId()+":"+goodId,SeckillOrder.class);
        if(seckillOrder != null){
            return Result.error(CodeMsg.REPEAT_SECKILL_OP);
        }
        //在上述条件都通行的时候,才允许进行秒杀操作,此时判断缓存中的库存是否还有
        //利用redis的原子性递减,保证了成功进入到秒杀操作的不会超过缓存中的库存
        boolean b = redisServer.setNx(user.getId()+"","1");
        if(!b){
            return Result.error(CodeMsg.REPEAT_SECKILL_OP);
        }
        Long stock = redisServer.decr(SeckillGoodKeyPrefix.SECKILL_GOOD_STOCK, goodId + "");
        if(stock < 0){
            //库存被秒杀完,进行本地标记秒杀结束,不需要再远程redis
            localSign.put(SeckillGoodKeyPrefix.GOOD_STOCK+goodId,true);
            return Result.error(CodeMsg.SECKILL_OVER);
        }
        //成功进入的进行下面的秒杀操作
        //String orderInfo = seckillService.doSeckill(user.getId(),goodId);
        OrderMessage orderMessage = new OrderMessage();
        orderMessage.setGoodId(goodId);
        orderMessage.setUserId(user.getId());
        orderMessage.setUuid(uuid);
        mqSender.sendOrderMessage(orderMessage);
        return Result.success(0);
    }
    /**
     * 秒杀请求处理
     * @param user
     * @param
     * @return
     */
    /*@RequestMapping("/do_seckill")
    public String do_seckill(User user, Long goodId, Model model){
        //用户如果没有登录,则返回登录界面
        if(user==null){
            return "redirect:/login.html";
        }
        GoodVo goodVo = seckillGoodService.get(goodId);
        if(goodVo == null){
            return "/seckill_error.html";
        }
        //如果秒杀未开始,则表示当前操作非法
        if(goodVo.getStartDate().getTime() - new Date().getTime() > 0){
            return "/seckill_error.html";
        }
        //判断当前秒杀商品是否还有存库
        if(goodVo.getStockCount()<=0){
            //没有则跳到秒杀活动结束页面
            return "/seckill_over.html";
        }
        //同一用户不可重复秒杀判断 查询当前用户是否已经秒杀过此商品
        SeckillOrder seckillOrder = seckillOrderService.getSeckillOrder(user.getId(),goodId);
        if(seckillOrder != null){
            return "/seckill_repeat.html";
        }
        OrderInfo orderInfo = seckillService.doSeckill(user.getId(),goodId);
        model.addAttribute("good",goodVo);
        model.addAttribute("order",orderInfo);
        return "order_detail";
    }*/

    /**
     * 根据订单号获取订单信息
     * @param user
     * @param orderNo
     * @return
     */
    @RequestMapping("/to_orderInfo")
    @ResponseBody
    public Result to_orderInfo(User user,String orderNo){
        //用户未登录
        if(user == null){
            return Result.error(CodeMsg.TOKEN_INVALID);
        }
        //无效的订单号
        if(orderNo == null){
            return Result.error(CodeMsg.ORDER_NULL);
        }
        OrderInfo orderInfo = orderInfoService.get(orderNo);
        return Result.success(orderInfo);
    }
}
